package com.jimo.transadb

import android.annotation.SuppressLint
import android.app.PictureInPictureParams
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.PowerManager
import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.MutableLiveData
import com.jimo.transadb.adb.AbsAdbConnectionManager
import com.jimo.transadb.adb.AdbStream
import com.jimo.transadb.adb.LocalServices
import com.jimo.transadb.adb.android.AndroidUtils
import com.jimo.transadb.bean.MessageEvent
import com.jimo.transadb.databinding.ActivityMainBinding
import com.jimo.transadb.utils.NotificationUtils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.util.concurrent.Executors


class MainActivity : AppCompatActivity() {
    private var pairAddress: String = ""
    private var pairCode: String = ""
    private lateinit var binding: ActivityMainBinding
    private val executor = Executors.newFixedThreadPool(3)
    private var adbShellStream: AdbStream? = null
    private val connectAdb = MutableLiveData<Boolean>()
    private val commandOutput = MutableLiveData<CharSequence>()

    @Volatile
    private var clearEnabled = false
    private val outputGenerator = Runnable {
        try {
            BufferedReader(InputStreamReader(adbShellStream!!.openInputStream()))
                .use { reader ->
                    val sb = StringBuilder()
                    var s: String?
                    while (reader.readLine().also { s = it } != null) {
                        if (clearEnabled) {
                            sb.delete(0, sb.length)
                            clearEnabled = false
                        }
                        sb.append(s).append("\n")
                        commandOutput.postValue(sb)
                    }
                }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.ip.setText(AndroidUtils.getHostIpAddress(application))
        initPermission()
        initObserve()
        initClick()
        EventBus.getDefault().register(this);
    }

    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    @SuppressLint("BatteryLife")
    private fun initPermission() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(
                android.Manifest.permission.POST_NOTIFICATIONS,
            ),
            0
        )
        val intent = Intent()
        val powerManager = getSystemService(POWER_SERVICE) as PowerManager
        if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
            intent.action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
            intent.data = Uri.parse("package:$packageName")
            startActivity(intent)
        }
    }


    private fun initObserve() {
        connectAdb.observe(this) {
            if (it) {
                binding.connect.text = "断开连接"
                binding.connectStatus.text = "连接成功"
            } else {
                binding.connect.text = "连接adb"
                binding.connectStatus.text = "连接失败"
                binding.showCommandOutput.text = ""
            }

        }
        commandOutput.observe(this) {
            binding.showCommandOutput.text = it
        }
    }

    private fun initClick() {
        binding.connect.setOnClickListener {
            if (connectAdb.value == true) {
                disconnect()
            } else {
                connect(binding.ip.text.toString(), binding.port.text.toString().toInt())
            }
        }
        binding.exe.setOnClickListener {
            val text = binding.command.text.toString()
            execute(text)
            binding.command.text.clear()
        }
        binding.configfrp.setOnClickListener {
            val inten = Intent(this, FrpcConfigActivity::class.java)
            startActivity(inten)
        }
        binding.enterPip.setOnClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                enterPictureInPictureMode(PictureInPictureParams.Builder().build())
            }
        }
        binding.battery.setOnClickListener {
            val intent1 = Intent()
            intent1.action = Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS
            startActivity(intent1)
        }
        binding.startService.setOnClickListener {
            val intent = Intent(this, ForegroundService::class.java)
            ContextCompat.startForegroundService(this, intent)
        }
        binding.stopService.setOnClickListener {
            val intent = Intent(this, ForegroundService::class.java)
            stopService(intent)
        }
        binding.connectByPair.setOnClickListener {
            NotificationUtils.showNotifyIpaddress(this, true)
        }
    }

    private fun connect(address: String, port: Int) {
        executor.submit {
            try {
                val manager: AbsAdbConnectionManager = AdbConnectionManager.getInstance(application)
                if (manager.isConnected) {
                    connectAdb.postValue(true)
                    return@submit
                }
                val connectionStatus: Boolean = manager.connect(address, port)
                connectAdb.postValue(connectionStatus)
            } catch (th: Throwable) {
                th.printStackTrace()
                connectAdb.postValue(false)
            }
        }
    }

    private fun execute(command: String) {
        executor.submit {
            try {
                if (adbShellStream == null || adbShellStream!!.isClosed) {
                    val manager =
                        AdbConnectionManager.getInstance(getApplication())
                    adbShellStream = manager.openStream(LocalServices.SHELL)
                    Thread(outputGenerator).start()
                }
                if (command == "clear") {
                    clearEnabled = true
                }
                adbShellStream!!.openOutputStream().use { os ->
                    os.write(
                        String.format("%1\$s\n", command)
                            .toByteArray(StandardCharsets.UTF_8)
                    )
                    os.flush()
                    os.write("\n".toByteArray(StandardCharsets.UTF_8))
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun disconnect() {
        executor.submit {
            try {
                val manager =
                    AdbConnectionManager.getInstance(application)
                manager.disconnect()
                connectAdb.postValue(false)
            } catch (th: Throwable) {
                th.printStackTrace()
                connectAdb.postValue(true)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        closeAdb()
        EventBus.getDefault().unregister(this)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onReceive(e: MessageEvent) {
        if (e.type == MessageEvent.BUS_PARE_ADDRESS) {
            pairAddress = e.data as String
            NotificationUtils.showNotifyIpaddress(this, false)
        }
        if (e.type == MessageEvent.BUS_PARE_CODE) {
            pairCode = e.data as String
            Log.i("emmmmmm", "开始隐藏")
        }
    }

    private fun closeAdb() {
        executor.submit {
            try {
                if (adbShellStream != null) {
                    adbShellStream!!.close()
                }
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
            try {
                AdbConnectionManager.getInstance(getApplication())
                    .close()
            } catch (e: java.lang.Exception) {
                e.printStackTrace()
            }
        }
        executor.shutdown()
    }
}